﻿using System;
using System.Linq;

using Buddy.BehaviorTree;
using Buddy.Common;
using Buddy.CommonBot;
using Buddy.Swtor;
using Buddy.Swtor.Objects;

using WingIt;
using WingIt.Dynamics;
using WingIt.Routines.Mirrors;

using Action = Buddy.BehaviorTree.Action;


namespace WingIt.Routines
{
    //Neo93
    [RevisionControlId("$Id: Carnage_Combat.cs 705 2012-11-11 22:54:47Z Chinajade $")]
    public class MarauderCarnage_SentinelCombat : MirrorRoutine
    {
        // MAINTAINERS NOTES:
        // * You will notice that lambda expression argument names are unique (e.g., "darkWardOn", "darkWardWhen", "joltWhen"),
        //   instead of generic (e.g., "ctx", "ret", "on", "doWhen", "castWhen").  PLEASE honor this convention!
        //   This allows us to quickly localize problems when looking at user's logs.  When the BehaviorTree encounters an exception
        //   (e.g., "object not found"), the location where an exception is thrown is identifiable only through the name
        //   of the lambda expression argument.  Such is the nature of BehaviorTrees.

        [Behavior(BehaviorType.Pull)]
        [Class(CharacterClass.Warrior, AdvancedClass.Marauder, SkillTreeId.MarauderCarnage)]
        [Class(CharacterClass.Knight, AdvancedClass.Sentinel, SkillTreeId.SentinelCombat)]
        public static Composite MarauderCarnage_SentinelCombat_Pull()
        {
            return new PrioritySelector(
                LazyRaider.CreateBTPS_NotifyAndShortCircuitWhenCombatDisabled(),
                CreateBTPS.BWcoreFixup_WaitForHarvestComplete(),
                TargetSelect.CreateBTPS_UpdateForBattlefieldConditions(),

                MarauderCarnage_SentinelCombat_Combat()
                );
        }

        [Behavior(BehaviorType.Combat)]
        [Class(CharacterClass.Warrior, AdvancedClass.Marauder, SkillTreeId.MarauderCarnage)]
        [Class(CharacterClass.Knight, AdvancedClass.Sentinel, SkillTreeId.SentinelCombat)]
        public static Composite MarauderCarnage_SentinelCombat_Combat()
        {
            return new PrioritySelector(
                LazyRaider.CreateBTPS_NotifyAndShortCircuitWhenCombatDisabled(),
                TargetSelect.CreateBTPS_UpdateForBattlefieldConditions(),

                CreateBTPS.StopWithinRangeAndLoS(target => MyTarget, Global.Distance.Melee),

                //***General***
                Cast("Force Charge", forceChargeWhen => MyTarget.IsInRange(3f, 0.5f) && !MyTarget.IsCoverAffected), //+3 Rage/15s CD/30m Range - Pull
                Cast("Unleash", unleashWhen => Me.IsStunned),//Insignia/2m CD
                Cast("Frenzy", frenzyWhen => !Me.HasMirrorBuff("Fury")),

                //#Only 1 of these 3 buffs can be active at a time#
                new Decorator(processFuryWhen => Me.HasMirrorBuffStacks("Fury", 30),
                    new PrioritySelector(
                        BuffSelf("Bloodthirst"),//5m CD
                        BuffSelf("Predation", predationWhen => Me.HealthPercent <= 50 || (!MyTarget.IsInRange(2f) && !Me.CanMirrorCast("Force Charge", MyTarget))),
                        BuffSelf("Berserk")
                        )),
                //#
                Cast("Obfuscate", obfuscateWhen => MyTarget.Toughness == CombatToughness.Player || MyTarget.Toughness == CombatToughness.Strong),

                //**Defensive**
                BuffSelf("Cloak of Pain", cloakOfPainWhen => Me.HealthPercent <= Global.Health.High),//1m CD
                BuffSelf("Saber Ward", saberWardWhen => Me.HealthPercent <= Global.Health.Mid),//3m CD
                BuffSelf("Force Camouflage", forceCamouflageWhen => Me.HealthPercent <= Global.Health.Low),//45s CD
                BuffSelf("Undying Rage", undyingRageWhen => Me.HealthPercent <= Global.Health.OhShit),//1m15s CD

                //**Offensive**
                Cast("Vicious Throw", viciousThrowWhen => MyTarget.HealthPercent <= 30),//-3 Rage
                Cast("Pommel Strike", pommelStrikeWhen => MyTarget.IsStunned && (MyTarget.Toughness == CombatToughness.Standard || MyTarget.Toughness == CombatToughness.Weak)),//strong skill but only usable on stunned - normal or weak - enemys
                Cast("Battering Assault", batteringAssaultWhen => Me.ResourceStat <= 6),//+6 Rage/12s CD
                Cast("Smash", smashWhen => Me.MobCountAround(Global.Distance.Melee) >= 3 && Me.MobCountAttacking() >= 3),
                Cast("Sweeping Slash", sweepingSlashWhen => Me.MobCountAround(Global.Distance.Melee) >= 3 && Me.MobCountAttacking() >= 3),

                //**Interrupt**
                // NB: These are ordered by reach of the ability (shortest reach interrupt-ability first).  This is so we don't burn
                // a far-reaching interrupt on a target that is standing next to us.
                Cast("Disruption", disruptionOn => InterruptTarget, disruptionWhen => TargetSelect.ForInterrupt(c => c.IsInRange(0.4f)) != null),//4m
                Cast("Force Choke", forceChokeOn => InterruptTarget, forceChokeWhen => (TargetSelect.ForInterrupt(c => c.IsInRange(1f)) != null) || (Me.HealthPercent <= 30 && !Me.HasMirrorBuff("Saber Ward"))),//10m

                //**CC**
                new Decorator(crowdControlWhen => (CCTarget != null) && (Me.MobCountAround(0.5f) >= 3) && (Me.MobCountAttacking() >= 3),
                    new PrioritySelector(
                        Cast("Intimidating Roar", intimidatingRoarOn => CCTarget, intimidatingRoarWhen => Me.HealthPercent <= 60)
                        )),

                //*Carnage*
                Cast("Gore"),//TODO: Add Debuff name
                Cast("Ravage"),//27s CD
                Cast("Force Scream", forceScreamWhen => (Me.HasMirrorAbility("Sever") && Me.HasMirrorAbility("Towering Rage") && Me.HasMirrorBuff("Blood Frenzy")) || !Me.HasMirrorAbility("Sever")),
                Cast("Rupture", ruptureWhen => !MyTarget.HasDebuff("Bleeding") && MyTarget.HealthPercent >= 50),//-2Rage
                Cast("Massacre"),//-3Rage/15s CD
                Cast("Vicious Slash", viciiousSlashWhen => !Me.HasMirrorBuff("Massacre")),

                //*Rage*
                Cast("Assault"),

                //Movement
                CreateBTPS.MoveWithinRangeAndLoS(target => MyTarget, Global.Distance.Melee)
                );
        }
            
        [Behavior(BehaviorType.OutOfCombat)]
        [Class(CharacterClass.Warrior, AdvancedClass.Marauder, SkillTreeId.MarauderCarnage)]
        [Class(CharacterClass.Knight, AdvancedClass.Sentinel, SkillTreeId.SentinelCombat)]
        public static Composite MarauderCarnage_SentinelCombat_OutOfCombat()
        {
            // NB: Apparently, BWcore will call this routine when in combat on occasion.  It is also called while we're pulling.
            return (new PrioritySelector(
                TargetSelect.CreateBTPS_UpdateForBattlefieldConditions(),
                new Decorator(oocBuffWhen => !Me.IsMounted,
                    new PrioritySelector(
                        BuffSelf("Ataru Form"),
                        BuffSelf("Shii-Cho Form", shiiChoFormWhen => !Me.HasMirrorAbility("Ataru Form"))
                        ))
                ));
        }
    }
}
